package com.jyh.blog.strategy.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.jyh.blog.dao.UserDao;
import com.jyh.blog.dao.UserInfoDao;
import com.jyh.blog.dao.UserRoleDao;
import com.jyh.blog.dto.SocialTokenDTO;
import com.jyh.blog.dto.SocialUserInfoDTO;
import com.jyh.blog.dto.UserDetailDTO;
import com.jyh.blog.dto.UserInfoDTO;
import com.jyh.blog.entity.User;
import com.jyh.blog.entity.UserInfo;
import com.jyh.blog.entity.UserRole;
import com.jyh.blog.enums.RoleEnum;
import com.jyh.blog.exception.MyException;
import com.jyh.blog.service.impl.UserDetailsServiceImpl;
import com.jyh.blog.strategy.SocialLoginStrategy;
import com.jyh.blog.utils.BeanCopyUtils;
import com.jyh.blog.utils.IpUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Objects;

import static com.jyh.blog.constant.CommonConst.TRUE;
import static com.jyh.blog.enums.LoginTypeEnum.QQ;

public abstract class AbstractSocialLoginStrategyImpl implements SocialLoginStrategy {
    @Autowired
    UserDetailsServiceImpl userDetailsService;
    @Autowired
    private UserDao userDao;
    @Autowired
    private UserRoleDao userRoleDao;
    @Autowired
    private UserInfoDao userInfoDao;
    @Resource
    private HttpServletRequest request;

    @Override
    public UserInfoDTO login(String data) {
        // 创建登录信息
        UserDetailDTO userDetailDTO;
        // 获取第三方 token 信息，抽象方法
        SocialTokenDTO socialToken = getSocialToken(data);
        // 获取用户 ip
        String ipAddress = IpUtils.getIpAddress(request);
        String ipSource = IpUtils.getIpSource(ipAddress);
        // 判断是否注册
        User user = getUser(socialToken);
        if (Objects.nonNull(user)) {
            // 已注册，查询用户信息
            userDetailDTO = getUserDetails(user, ipAddress, ipSource);
        } else {
            // 未注册，新增用户
            userDetailDTO = saveUserDetails(socialToken,ipAddress,ipSource);
        }
        // 判断账户是否禁用
        if(userDetailDTO.getIsDisable()==TRUE){
            throw new MyException("该用户被禁用");
        }
        // 将用户登录信息交给 spring security 管理
        UsernamePasswordAuthenticationToken auth=new UsernamePasswordAuthenticationToken(userDetailDTO,null,userDetailDTO.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(auth);
        // 返回用户信息
        return BeanCopyUtils.copyObject(userDetailDTO,UserInfoDTO.class);
    }

    /**
     * 社交 token
     *
     * @param data
     * @return
     */
    public abstract SocialTokenDTO getSocialToken(String data);

    /**
     * 社交账号信息
     *
     * @param socialToken
     * @return
     */
    public abstract SocialUserInfoDTO getSocialUserInfo(SocialTokenDTO socialToken);

    /**
     * 新建用户
     *
     * @param socialToken
     * @return
     */
    private UserDetailDTO saveUserDetails(SocialTokenDTO socialToken,String ipAddress,String ipSource) {
        //获取第三方账号信息
        SocialUserInfoDTO socialUserInfo = getSocialUserInfo(socialToken);
        //保存用户信息
        UserInfo userInfo = UserInfo.builder()
                .avatar(socialUserInfo.getAvatar())
                .nickname(socialUserInfo.getNickname())
                .build();
        userInfoDao.insert(userInfo);
        //保存账号信息
        User user = User.builder()
                .userInfoId(userInfo.getId())
                .username(socialToken.getOpenId())
                .password(socialToken.getAccessToken())
                .loginType(socialToken.getLoginType())
                .lastLoginTime(LocalDateTime.now())
                .ipAddress(ipAddress)
                .ipSource(ipSource)
                .build();
        userDao.insert(user);
        //绑定角色
        userRoleDao.insert(UserRole.builder()
                .userId(userInfo.getId())
                .roleId(RoleEnum.USER.getRoleId())
                .build()
        );
        //封装用户
        return userDetailsService.convertUserDetail(user,request);
    }


    /**
     * 更新用户本次登录的信息后，将其转换为 UserDetailDTO 返回
     *
     * @param user
     * @param ipAddress
     * @param ipSource
     * @return
     */
    private UserDetailDTO getUserDetails(User user, String ipAddress, String ipSource) {
        userDao.update(new User(), new LambdaUpdateWrapper<User>()
                .set(User::getLastLoginTime, LocalDateTime.now())
                .set(User::getLoginType, QQ.getType())
                .set(User::getIpAddress, ipAddress)
                .set(User::getIpSource, ipSource)
                .eq(User::getId, user.getId())
        );
        return userDetailsService.convertUserDetail(user, request);
    }

    /**
     * 根据 socialToken 中的 openId、loginType 查询数据库
     *
     * @param socialToken
     * @return
     */
    private User getUser(SocialTokenDTO socialToken) {
        return userDao.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, socialToken.getOpenId())
                .eq(User::getLoginType, socialToken.getLoginType())
        );
    }
}
